<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title>TS100 Translation Parser</title>

		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script src="translations_commons.js"></script>
		<script src="translations_def.js"></script>
		<script>

	var app;
	var defMap = {};
	var langMap = {};
	var lang;

	var defMsgMap;
	var defCharMap; 	
	var defGrpMap;	
	var defOptMap;	
	
	function save(langCode){
		saveJSON(langMap[langCode], "translation_"+langCode.toLowerCase()+".json");
	}

	function view(langCode){
		showJSON(langMap[langCode], "translation_"+langCode.toLowerCase()+".json");
	}

	function translationFileSelected(e) {
		var target = e;
		var id = target.id;
		
		var file = target.files[0];
		if (!file) {
			return;
		}
		var fr = new FileReader();
		fr.onload = function(e) {
			parseTranslationFile(file.name, e.target.result);
		}
		fr.readAsText(file);
		
	}
	
	function parseTranslationFile(name, src) {
		// remove multiline comments
		src = src.replace(/\/\*[\s\S.]*?\*\//mg, "");
		// remove single-line comments
		src = src.replace(/\/\/.*/mg, "");
		// remove empty lines
		src = src.replace(/^\s*\n/gm, "");
		
		var langCode = "";
		var srcLines = src.split("\n");

		var reMessage = /const\s+char\s*\*\s+([\w\d]+)\s*=\s*"(.*)"/;
		var reSettingsDescStart = /const\s+char\s*\*\s+SettingsDescriptions\[/;
		var reSettingsNamesStart = /const\s+char\s*\*\s+SettingsShortNames\[/;
		var reSettingsMenuDescStart = /const\s+char\s*\*\s+SettingsMenuEntriesDescriptions\[/;
		var reChar = /const\s+char\s+([\w\d]+)\s*=\s*'(\w)'/;
		var reMenuMode = /SettingsShortNameType\s*=\s*SHORT_NAME_(\w+)_LINE/;
		
		var reMenuStart = /\s*const\s+char\s*\*\s+SettingsMenuEntries\[/;

//		var reString = /^\s*"(.*)"/;
		var reString = /"(.*)"/;
		var reSingleLine = /{\s*"(.*)"\s*}/;
		var reDoubleLine = /{\s*"(.*)"\s*,\s*"(.*)"\s*}/;
		
		var mode = '';
		var entryIndex = 0;
		for (var li = 0; li < srcLines.length; li++) {
			// trim lines
			line = srcLines[li] = srcLines[li].trim();
			
			// if entering a new lang block
			if (startsWith(line, "#ifdef LANG_")) {
				mode = 'new-language';
				langCode = line.substring(12);
				lang = langMap[langCode];
				// use existing or instantiate new
				if (!isDefined(lang)) {
					lang = {
						languageCode: langCode,
						messages: {},
						characters: {},
						menuDouble : false,
						menuGroups: {},
						menuOptions: {}
					};
					langMap[langCode] = lang;
					app.languages[app.languages.length] = langCode;
				}
				entryIndex = 0;
				continue;
			}

			// Menu type
			reMenuMode.lastIndex = 0;
			match = reMenuMode.exec(line);
			if (match) {
				lang.menuDouble = match[1] == 'DOUBLE';
				entryIndex = 0;
				continue;
			}
			
			// Messages
			reMessage.lastIndex = 0;
			match = reMessage.exec(line);
			if (match) {
				lang.messages[match[1]] = xunescape(match[2]);
				entryIndex = 0;
				continue;
			}
			
			// Chars descriptions
			reChar.lastIndex = 0;
			match = reChar.exec(line);
			if (match) {
				// found description block start
				mode = 'char';
				lang.characters[match[1]] = xunescape(match[2]);
				entryIndex = 0;
				continue;
			}
			// Settings descriptions
			reSettingsDescStart.lastIndex = 0;
			match = reSettingsDescStart.exec(line);
			if (match) {
				// found description block start
				mode = 'settingsDesc';
				entryIndex = 0;
				continue;
			}
			reSettingsNamesStart.lastIndex = 0;
			match = reSettingsNamesStart.exec(line);
			if (match) {
				// found description block start
				mode = 'settingsNames';
				entryIndex = 0;
				continue;
			}
			reMenuStart.lastIndex = 0;
			match = reMenuStart.exec(line);
			if (match) {
				// found description block start
				mode = 'menu';
				entryIndex = 0;
				continue;
			}
			reSettingsMenuDescStart.lastIndex = 0;
			match = reSettingsMenuDescStart.exec(line);
			if (match) {
				// found description block start
				mode = 'menuDesc';
				entryIndex = 0;
				continue;
			}
			
			if (mode == 'menu') {
				// processing menu group names
				reString.lastIndex = 0;
				match = reString.exec(line);
				if (match) {
					// found description string
					var entry = getMenuGroup(entryIndex);
					var m = match[1].split("\\n");
					entry.text2[0] = xunescape(m[0]);
					entry.text2[1] = xunescape(m[1]);
					entryIndex++;
				}
			} else if (mode == 'menuDesc') {
				// processing menu group descriptions
				reString.lastIndex = 0;
				match = reString.exec(line);
				if (match) {
					// found description string
					var entry = getMenuGroup(entryIndex);
					entry.desc = xunescape(match[1]);
					entryIndex++;
				}
			} else if (mode == 'settingsDesc') {
				// processing option descriptions
				reString.lastIndex = 0;
				match = reString.exec(line);
				if (match) {
					// found description string
					var entry = getMenuOption(entryIndex);
					entry.desc = xunescape(match[1]);
					entryIndex++;
				}
			} else if (mode == 'settingsNames') {
				reDoubleLine.lastIndex = 0;
				match = reDoubleLine.exec(line);
				if (match) {
					var entry = getMenuOption(entryIndex);
					entry.text2[0] = xunescape(match[1]);
					entry.text2[1] = xunescape(match[2]);
					entryIndex++;
				} else {
					reSingleLine.lastIndex = 0;
					match = reSingleLine.exec(line);
					if (match) {
						var entry = getMenuOption(entryIndex);
						entry.text = xunescape(match[1]);
						entryIndex++;
					}

				}
			}
		}
		app.done = 1;
	}

	function getMenuOption(entryIndex) {
		var optionDef = def.menuOptions[entryIndex];
		if (!isDefined(optionDef)) {
			var s = "Could not find menu option with index "+entryIndex;
			alert(s);
			throw s;
		}
		var id = optionDef.id;
		var entry = lang.menuOptions[id];
		if (!isDefined(entry)) {
			entry =
			{
				"text": "",
				"text2": ["", ""],
				"desc": ""
			}
			lang.menuOptions[id] = entry;
		}
		return entry;
	}
	
	function getMenuGroup(entryIndex) {
		var optionDef = def.menuGroups[entryIndex];
		if (!isDefined(optionDef)) {
			var s = "Could not find menu group with index "+entryIndex;
			alert(s);
			throw s;
		}
		var id = optionDef.id;
		var entry = lang.menuGroups[id];
		if (!isDefined(entry)) {
			entry =
			{
				"text2": ["", ""],
				"desc": ""
			}
			lang.menuGroups[id] = entry;
		}
		return entry;
	}
	
	function markSaved(lang) {
		document.getElementById("row_"+lang).classList.add("saved");
	}
	
	function loaded() {
		app = new Vue({
			el : '#app',
			data : {
				languages: [],
				done : false,
				def : {
				}
				
			},
			methods : {
				vSave : function(lang) {
					save(lang);
					markSaved(lang);
				},
				vView : function(lang) {
					view(lang);
					markSaved(lang);
				}
			}
		});
		
		app.def = def;
		defMsgMap = copyArrayToMap(app.def.messages);
		defCharMap = copyArrayToMap(app.def.characters);
		defGrpMap = copyArrayToMap(app.def.menuGroups);
		defOptMap = copyArrayToMap(app.def.menuOptions);
	}

	window.onload=loaded;
</script>
	<link href="translations.css" rel="stylesheet" type="text/css">
	</head>
	<body>

		<div id="app">
			<h1>TS100 Translation Parser</h1>
			<table class="header data">
				<tr>
					<td class="label">Translation.cpp</td>
					<td class="value">
						<input type="file" id="translation-cpp-file" onchange="translationFileSelected(this)" accept=".cpp">
					</td>
				</tr>
			</table>
			
			<div class="data" v-if="done">
				<div class="value" v-for="lang in languages" :id="'row_'+lang">
					<input type="button" :value="'Save '+lang" v-on:click="vSave(lang)">
					<input type="button" :value="'View '+lang" v-on:click="vView(lang)">
				</div>
			</div>
				
		</div>
	</body>
</html>